/*!
 * imagesLoaded PACKAGED v4.1.4
 * JavaScript is all like "You images are done yet or what?"
 * MIT License
 */

/**
 * EvEmitter v1.1.0
 * Lil' event emitter
 * MIT License
 */

/* jshint unused: true, undef: true, strict: true */

(function (global, factory) {
  // universal module definition
  /* jshint strict: false */ /* globals define, module, window */
  if (typeof define == 'function' && define.amd) {
    // AMD - RequireJS
    define('ev-emitter/ev-emitter', factory);
  } else if (typeof module == 'object' && module.exports) {
    // CommonJS - Browserify, Webpack
    module.exports = factory();
  } else {
    // Browser globals
    global.EvEmitter = factory();
  }

}(typeof window != 'undefined' ? window : this, function () {



  function EvEmitter() { }

  var proto = EvEmitter.prototype;

  proto.on = function (eventName, listener) {
    if (!eventName || !listener) {
      return;
    }
    // set events hash
    var events = this._events = this._events || {};
    // set listeners array
    var listeners = events[eventName] = events[eventName] || [];
    // only add once
    if (listeners.indexOf(listener) == -1) {
      listeners.push(listener);
    }

    return this;
  };

  proto.once = function (eventName, listener) {
    if (!eventName || !listener) {
      return;
    }
    // add event
    this.on(eventName, listener);
    // set once flag
    // set onceEvents hash
    var onceEvents = this._onceEvents = this._onceEvents || {};
    // set onceListeners object
    var onceListeners = onceEvents[eventName] = onceEvents[eventName] || {};
    // set flag
    onceListeners[listener] = true;

    return this;
  };

  proto.off = function (eventName, listener) {
    var listeners = this._events && this._events[eventName];
    if (!listeners || !listeners.length) {
      return;
    }
    var index = listeners.indexOf(listener);
    if (index != -1) {
      listeners.splice(index, 1);
    }

    return this;
  };

  proto.emitEvent = function (eventName, args) {
    var listeners = this._events && this._events[eventName];
    if (!listeners || !listeners.length) {
      return;
    }
    // copy over to avoid interference if .off() in listener
    listeners = listeners.slice(0);
    args = args || [];
    // once stuff
    var onceListeners = this._onceEvents && this._onceEvents[eventName];

    for (var i = 0; i < listeners.length; i++) {
      var listener = listeners[i]
      var isOnce = onceListeners && onceListeners[listener];
      if (isOnce) {
        // remove listener
        // remove before trigger to prevent recursion
        this.off(eventName, listener);
        // unset once flag
        delete onceListeners[listener];
      }
      // trigger listener
      listener.apply(this, args);
    }

    return this;
  };

  proto.allOff = function () {
    delete this._events;
    delete this._onceEvents;
  };

  return EvEmitter;

}));

/*!
 * imagesLoaded v4.1.4
 * JavaScript is all like "You images are done yet or what?"
 * MIT License
 */

(function (window, factory) {
  'use strict';
  // universal module definition

  /*global define: false, module: false, require: false */

  if (typeof define == 'function' && define.amd) {
    // AMD
    define([
      'ev-emitter/ev-emitter'
    ], function (EvEmitter) {
      return factory(window, EvEmitter);
    });
  } else if (typeof module == 'object' && module.exports) {
    // CommonJS
    module.exports = factory(
      window,
      require('ev-emitter')
    );
  } else {
    // browser global
    window.imagesLoaded = factory(
      window,
      window.EvEmitter
    );
  }

})(typeof window !== 'undefined' ? window : this,

  // --------------------------  factory -------------------------- //

  function factory(window, EvEmitter) {



    var $ = window.jQuery;
    var console = window.console;

    // -------------------------- helpers -------------------------- //

    // extend objects
    function extend(a, b) {
      for (var prop in b) {
        a[prop] = b[prop];
      }
      return a;
    }

    var arraySlice = Array.prototype.slice;

    // turn element or nodeList into an array
    function makeArray(obj) {
      if (Array.isArray(obj)) {
        // use object if already an array
        return obj;
      }

      var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
      if (isArrayLike) {
        // convert nodeList to array
        return arraySlice.call(obj);
      }

      // array of single index
      return [obj];
    }

    // -------------------------- imagesLoaded -------------------------- //

    /**
     * @param {Array, Element, NodeList, String} elem
     * @param {Object or Function} options - if function, use as callback
     * @param {Function} onAlways - callback function
     */
    function ImagesLoaded(elem, options, onAlways) {
      // coerce ImagesLoaded() without new, to be new ImagesLoaded()
      if (!(this instanceof ImagesLoaded)) {
        return new ImagesLoaded(elem, options, onAlways);
      }
      // use elem as selector string
      var queryElem = elem;
      if (typeof elem == 'string') {
        queryElem = document.querySelectorAll(elem);
      }
      // bail if bad element
      if (!queryElem) {
        console.error('Bad element for imagesLoaded ' + (queryElem || elem));
        return;
      }

      this.elements = makeArray(queryElem);
      this.options = extend({}, this.options);
      // shift arguments if no options set
      if (typeof options == 'function') {
        onAlways = options;
      } else {
        extend(this.options, options);
      }

      if (onAlways) {
        this.on('always', onAlways);
      }

      this.getImages();

      if ($) {
        // add jQuery Deferred object
        this.jqDeferred = new $.Deferred();
      }

      // HACK check async to allow time to bind listeners
      setTimeout(this.check.bind(this));
    }

    ImagesLoaded.prototype = Object.create(EvEmitter.prototype);

    ImagesLoaded.prototype.options = {};

    ImagesLoaded.prototype.getImages = function () {
      this.images = [];

      // filter & find items if we have an item selector
      this.elements.forEach(this.addElementImages, this);
    };

    /**
     * @param {Node} element
     */
    ImagesLoaded.prototype.addElementImages = function (elem) {
      // filter siblings
      if (elem.nodeName == 'IMG') {
        this.addImage(elem);
      }
      // get background image on element
      if (this.options.background === true) {
        this.addElementBackgroundImages(elem);
      }

      // find children
      // no non-element nodes, #143
      var nodeType = elem.nodeType;
      if (!nodeType || !elementNodeTypes[nodeType]) {
        return;
      }
      var childImgs = elem.querySelectorAll('img');
      // concat childElems to filterFound array
      for (var i = 0; i < childImgs.length; i++) {
        var img = childImgs[i];
        this.addImage(img);
      }

      // get child background images
      if (typeof this.options.background == 'string') {
        var children = elem.querySelectorAll(this.options.background);
        for (i = 0; i < children.length; i++) {
          var child = children[i];
          this.addElementBackgroundImages(child);
        }
      }
    };

    var elementNodeTypes = {
      1: true,
      9: true,
      11: true
    };

    ImagesLoaded.prototype.addElementBackgroundImages = function (elem) {
      var style = getComputedStyle(elem);
      if (!style) {
        // Firefox returns null if in a hidden iframe https://bugzil.la/548397
        return;
      }
      // get url inside url("...")
      var reURL = /url\((['"])?(.*?)\1\)/gi;
      var matches = reURL.exec(style.backgroundImage);
      while (matches !== null) {
        var url = matches && matches[2];
        if (url) {
          this.addBackground(url, elem);
        }
        matches = reURL.exec(style.backgroundImage);
      }
    };

    /**
     * @param {Image} img
     */
    ImagesLoaded.prototype.addImage = function (img) {
      var loadingImage = new LoadingImage(img);
      this.images.push(loadingImage);
    };

    ImagesLoaded.prototype.addBackground = function (url, elem) {
      var background = new Background(url, elem);
      this.images.push(background);
    };

    ImagesLoaded.prototype.check = function () {
      var _this = this;
      this.progressedCount = 0;
      this.hasAnyBroken = false;
      // complete if no images
      if (!this.images.length) {
        this.complete();
        return;
      }

      function onProgress(image, elem, message) {
        // HACK - Chrome triggers event before object properties have changed. #83
        setTimeout(function () {
          _this.progress(image, elem, message);
        });
      }

      this.images.forEach(function (loadingImage) {
        loadingImage.once('progress', onProgress);
        loadingImage.check();
      });
    };

    ImagesLoaded.prototype.progress = function (image, elem, message) {
      this.progressedCount++;
      this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded;
      // progress event
      this.emitEvent('progress', [this, image, elem]);
      if (this.jqDeferred && this.jqDeferred.notify) {
        this.jqDeferred.notify(this, image);
      }
      // check if completed
      if (this.progressedCount == this.images.length) {
        this.complete();
      }

      if (this.options.debug && console) {
        console.log('progress: ' + message, image, elem);
      }
    };

    ImagesLoaded.prototype.complete = function () {
      var eventName = this.hasAnyBroken ? 'fail' : 'done';
      this.isComplete = true;
      this.emitEvent(eventName, [this]);
      this.emitEvent('always', [this]);
      if (this.jqDeferred) {
        var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve';
        this.jqDeferred[jqMethod](this);
      }
    };

    // --------------------------  -------------------------- //

    function LoadingImage(img) {
      this.img = img;
    }

    LoadingImage.prototype = Object.create(EvEmitter.prototype);

    LoadingImage.prototype.check = function () {
      // If complete is true and browser supports natural sizes,
      // try to check for image status manually.
      var isComplete = this.getIsImageComplete();
      if (isComplete) {
        // report based on naturalWidth
        this.confirm(this.img.naturalWidth !== 0, 'naturalWidth');
        return;
      }

      // If none of the checks above matched, simulate loading on detached element.
      this.proxyImage = new Image();
      this.proxyImage.addEventListener('load', this);
      this.proxyImage.addEventListener('error', this);
      // bind to image as well for Firefox. #191
      this.img.addEventListener('load', this);
      this.img.addEventListener('error', this);
      this.proxyImage.src = this.img.src;
    };

    LoadingImage.prototype.getIsImageComplete = function () {
      // check for non-zero, non-undefined naturalWidth
      // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671
      return this.img.complete && this.img.naturalWidth;
    };

    LoadingImage.prototype.confirm = function (isLoaded, message) {
      this.isLoaded = isLoaded;
      this.emitEvent('progress', [this, this.img, message]);
    };

    // ----- events ----- //

    // trigger specified handler for event type
    LoadingImage.prototype.handleEvent = function (event) {
      var method = 'on' + event.type;
      if (this[method]) {
        this[method](event);
      }
    };

    LoadingImage.prototype.onload = function () {
      this.confirm(true, 'onload');
      this.unbindEvents();
    };

    LoadingImage.prototype.onerror = function () {
      this.confirm(false, 'onerror');
      this.unbindEvents();
    };

    LoadingImage.prototype.unbindEvents = function () {
      this.proxyImage.removeEventListener('load', this);
      this.proxyImage.removeEventListener('error', this);
      this.img.removeEventListener('load', this);
      this.img.removeEventListener('error', this);
    };

    // -------------------------- Background -------------------------- //

    function Background(url, element) {
      this.url = url;
      this.element = element;
      this.img = new Image();
    }

    // inherit LoadingImage prototype
    Background.prototype = Object.create(LoadingImage.prototype);

    Background.prototype.check = function () {
      this.img.addEventListener('load', this);
      this.img.addEventListener('error', this);
      this.img.src = this.url;
      // check if image is already complete
      var isComplete = this.getIsImageComplete();
      if (isComplete) {
        this.confirm(this.img.naturalWidth !== 0, 'naturalWidth');
        this.unbindEvents();
      }
    };

    Background.prototype.unbindEvents = function () {
      this.img.removeEventListener('load', this);
      this.img.removeEventListener('error', this);
    };

    Background.prototype.confirm = function (isLoaded, message) {
      this.isLoaded = isLoaded;
      this.emitEvent('progress', [this, this.element, message]);
    };

    // -------------------------- jQuery -------------------------- //

    ImagesLoaded.makeJQueryPlugin = function (jQuery) {
      jQuery = jQuery || window.jQuery;
      if (!jQuery) {
        return;
      }
      // set local variable
      $ = jQuery;
      // $().imagesLoaded()
      $.fn.imagesLoaded = function (options, callback) {
        var instance = new ImagesLoaded(this, options, callback);
        return instance.jqDeferred.promise($(this));
      };
    };
    // try making plugin
    ImagesLoaded.makeJQueryPlugin();

    // --------------------------  -------------------------- //

    return ImagesLoaded;

  });